// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
use bcrypt::{hash, verify, DEFAULT_COST};
use chrono::Local;
use serde::{Deserialize, Serialize};
use std::env;
use std::path::Path;
use futures_util::stream::StreamExt;
use mongodb::{
    bson::doc,
    options::{
         FindOneOptions, 
         UpdateOptions, 
    },
    IndexModel,
};
mod connectmongodb;
mod localfiles;

#[derive(Debug, Serialize, Deserialize)]
pub struct OSSAccess {
  oss_access_id: String,
  oss_key_secret: String,
  reigion : String,
  bucket : String
}

#[derive(Debug, Serialize, Deserialize)]
pub struct OldandNewPassword{
  old_password: String,
  new_password: String,
}

#[tauri::command]
async fn login(
    user: connectmongodb::User,
    mongodb_url: String
) -> Result<String, String> {
    let url = mongodb_url.clone();
    let users_collection =
     connectmongodb::from_client_get_users_collection(url).await?;
    let username = user.username;
    let password = user.password;
    let find_user = users_collection.find_one(doc! { "username": &username })
        .await
        .map_err(|e| format!("❌Database error: {}", e))?;
    println!(
        "Login attempt: username={}, password={}",
        username, password);
    match find_user {
        Some(find_user) => {
            // 验证密码
            let password_match = verify(&password, &find_user.password)
                .map_err(|e| format!("Password verification error: {}", e))?;
            if password_match {
                return Ok(String::from("✅Login successful"));
            } else {
                return Err(String::from("❌Invalid username or password"));
            }
        }
        None => return Err(String::from("❌Invalid username or password")),
    }
}

#[tauri::command]
async fn register(
    oss_access : OSSAccess,
    user : connectmongodb::User,
    mongodb_url: String
)-> Result<String, String> {
    // 连接到 MongoDB
    // 检查用户名是否已存在
    let username = user.username;
    let oss_username = username.clone();
    let password = user.password;
    let url = mongodb_url.clone();
    let oss_url = url.clone();
    let users_collection = 
    connectmongodb::from_client_get_users_collection(url).await?;
    let oss_collection = 
    connectmongodb::from_client_get_oss_collection(oss_url).await?;

    let existing_user = users_collection
        .find_one(doc! { "username": &username })
        .await
        .map_err(|e| format!("Database error: {}", e))?;
    println!("Register attempt: username={}, password={}", username, password);
    if existing_user.is_some() {
        return Err(String::from("Username already exists"));
    }
    let index_model = IndexModel::builder().keys(doc! { "username": 1 })
        .build();
    users_collection.create_index(index_model)
        .await
        .map_err(|e| format!("❌Failed to create index: {}", e))?;
    // 按用户名创建索引
    // 哈希密码
    let hashed_password =
        hash(password, DEFAULT_COST).map_err(|e| format!("Password hashing error: {}", e))?;
    // 创建新用户
    let new_user = connectmongodb::User {
        username,
        password: hashed_password,
    };
    // 插入用户到数据库
    users_collection.insert_one(new_user)
        .await
        .map_err(|e| format!("Failed to insert user: {}", e))?;

    let filter = doc! { "username": oss_username };
    let options = UpdateOptions::builder().upsert(true).build();

    let hashed_osscret =
        hash(oss_access.oss_key_secret, DEFAULT_COST)
        .map_err(|e| format!("Password hashing error: {}", e))?;
    // 添加chrono时间生成
    let update = doc! {
        "$set": { 
            "id" : oss_access.oss_access_id,
            "secret" : hashed_osscret,
            "reigion" : oss_access.reigion,
            "bucket" : oss_access.bucket
        }
    };
    let oss_index_model = IndexModel::builder()
        .keys(doc! { "username" : 1 })
        .build();
    oss_collection.update_one( filter, update ).with_options(options)
        .await
        .map_err(|e| format!("❌Failed to save path: {}", e))?;
    oss_collection.create_index(oss_index_model)
        // .with_options(CreateIndexOptions::builder().unique(true).build())
        .await
        .map_err(|e| format!("❌Failed to create index: {}", e))?;
    return Ok(String::from("Registration successful"));
}

// 添加删除账户的函数
#[tauri::command]
async fn delete_account(
    user : connectmongodb::User,
    mongodb_url : String
)-> Result<String, String> {
    let username = user.username;
    // 连接到 MongoDB
    let users_collection = 
    connectmongodb::from_client_get_users_collection(mongodb_url).await?;
    // 删除用户
    let result = users_collection
        .delete_one(doc! { "username": &username })
        .await
        .map_err(|e| format!("❌Failed to delete user: {}", e))?;
    if result.deleted_count == 0 {
        return Err(format!("❌User '{}' not found", username));
    }
    Ok(format!("User '{}' has been deleted successfully", username))
}

// 添加修改密码的函数
#[tauri::command]
async fn change_password(
    user : connectmongodb::User,
    old_new_password: OldandNewPassword,
    mongodb_url : String
) -> Result<String, String> {
    // 连接到 MongoDB
    let users_collection 
        = connectmongodb::from_client_get_users_collection(mongodb_url).await?;
    let username = user.username;
    // println!("username {}", &username);
    // 使用投影仅获取必要字段
    // let find_one_options = FindOneOptions::builder()
    //     .projection(doc! { 
    //         "_id": 0,
    //         "username": 1,
    //         "password": 1,
    //     }).build();
    let find_user = users_collection.find_one(doc! { "username": &username })
    .await
    .map_err(|e| format!("❌Database error: {}", e))?
    .ok_or_else(|| "❌User not found".to_string())?;
    // .with_options(find_one_options)
    let oldpassword = old_new_password.old_password;
    let newpassword = old_new_password.new_password;
    // 验证旧密码
    println!("user password {}", &find_user.password);
    println!("old password {}", &oldpassword);
    let is_valid = verify(&oldpassword, &find_user.password)
        .map_err(|e| format!("❌Password verification error: {}", e))?;
    if !is_valid {
        return Err("❌Current password is incorrect".to_string());
    }
    // 哈希新密码
    let hashed_password = hash(&newpassword, DEFAULT_COST)
        .map_err(|e| format!("❌Password hashing error: {}", e))?;
    // 更新密码
    let update = doc! { "$set": { "password": hashed_password } };
    let filter = doc! { "username": &username };
    users_collection.update_one(filter, update).await
        .map_err(|e| format!("❌Failed to update password: {}", e))?;
    Ok("✅Password changed successfully".to_string())
}

#[tauri::command]
async fn save_cloud_path(
    user : connectmongodb::User,
    mongodb_url: String,
    file_path: String,
) -> Result<(), String> {
    let username = user.username;
    let users_collection 
        = connectmongodb::from_client_get_paths_collection(mongodb_url).await?;
    let filter = doc! { "username": &username, "path": &file_path };
    let options = UpdateOptions::builder().upsert(true).build();
    // 添加chrono时间生成
    let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
    let update = doc! {
        "$set": { "timestamp": timestamp }
    };
    let path_index_model = IndexModel::builder()
        .keys(doc! { "path": 1, "username" : 1 })
        .build();

    users_collection.update_one(filter, update)
        .with_options(options)
        .await
        .map_err(|e| format!("❌Failed to save path: {}", e))?;
    users_collection.create_index(path_index_model)
        .await
        .map_err(|e| format!("❌Failed to create index: {}", e))?;
    println!("saved to the database");
    Ok(())
}

#[tauri::command]
async fn get_oss_accesskey(
    user : connectmongodb::User,
    mongodb_url: String
) -> Result<OSSAccess, String> {
    let username = user.username;
    let url = mongodb_url.clone();
    let oss_collection = 
    connectmongodb::from_client_get_oss_collection(url).await?;
    let filter = doc! { "username": &username };
    let find_one_options = FindOneOptions::builder()
        .projection(doc! { 
            "_id": 0,
            "id": 1,
            "secret": 1,
            "reigion": 1,
            "bucket": 1,
        }).build();
    let oss_accesskey = oss_collection
        .find_one(filter)
        .with_options(find_one_options)
        .await
        .map_err(|e| format!("❌Database error: {}", e))?
        .ok_or_else(|| "❌User not found".to_string())?;
    Ok(OSSAccess {
        oss_access_id: oss_accesskey.get("id").and_then(|p| p.as_str()).unwrap_or("").to_string(),
        oss_key_secret: oss_accesskey.get("secret").and_then(|p| p.as_str()).unwrap_or("").to_string(),
        bucket: oss_accesskey.get("bucket").and_then(|p| p.as_str()).unwrap_or("").to_string(),
        reigion: oss_accesskey.get("reigion").and_then(|p| p.as_str()).unwrap_or("").to_string(),
    })
}

async fn get_each_cloud_file(path: String, timestamp: String)
-> Result<localfiles::FileItem, String>{
    let metadata = std::fs::metadata(&path)
    .map_err(|e| e.to_string())?;
    let name = Path::new(&path).file_name()
    .and_then(|name| name.to_str())
    .unwrap_or("")
    .to_string();
    println!("uploaded file name {}", name);
    Ok(localfiles::FileItem{
        name,
        path: path.to_string(),
        is_dir: metadata.is_dir(), // Cloud paths are always files
        size: metadata.len(),      // Size not stored in DB
        timestamp: timestamp.to_string()
    })
}

#[tauri::command]
// 获取所有云端文件路径
async fn check_cloud_files(
    user: connectmongodb::User,
    mongodb_url: String
)-> Result<Vec<localfiles::FileItem>, String> {
    let mut user_doc = 
    connectmongodb::get_userdoc(user.clone(), mongodb_url.clone()).await?;
    let mut file_items = Vec::new();
    while let Some(doc) = user_doc.next().await {
        let document = doc.map_err(|e| format!("failed to analyze: {}", e))?;
        let path = document.get("path")
        .and_then(|p| p.as_str()).ok_or("Invalid path")?;
        // 新增文件存在性检查
        let path_obj = Path::new(path);
        if !path_obj.exists() {
            eprintln!("⚠️File not found: {}", path);
            delete_cloud_path(
                user.clone(),
                mongodb_url.clone(),
                path.to_string()
            ).await.map_err(|e| format!("❌Failed to delete path: {}", e))?;
            continue; // 跳过不存在的文件
        }
        let timestamp = document.get("timestamp")
        .and_then(|p| p.as_str()).ok_or("Invalid path")?;
        match get_each_cloud_file(path.to_string(), timestamp.to_string()).await {
            Ok(item) => file_items.push(item),
            Err(e) => eprintln!("Skipping invalid document: {}", e),
        }
    }
    Ok(file_items)
}
  
#[tauri::command]
async fn delete_cloud_path(
    user : connectmongodb::User,
    mongodb_url: String,
    file_path : String,
) -> Result<(), String> {
    let username = user.username;
    let collection = 
    connectmongodb::from_client_get_paths_collection(mongodb_url).await?;
    let filter = doc! {
        "path": file_path,
        "username": &username
    };
    collection.delete_one(filter).await
        .map_err(|e| format!("❌Failed to remove path: {}", e))?;
    Ok(())
}

// 在invoke_handler中注册命令
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    // 创建应用状态
    tauri::Builder::default()
        .plugin(tauri_plugin_http::init())
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_dialog::init())
        .invoke_handler(tauri::generate_handler![
            login,
            register,
            delete_account,
            change_password,
            save_cloud_path,
            check_cloud_files,
            delete_cloud_path,
            get_oss_accesskey,
            localfiles::open_file,
            localfiles::list_directory,
            localfiles::read_file_content,
            localfiles::delete_file,
            localfiles::read_file_bytes,
            localfiles::write_file_bytes,
            localfiles::write_text_file,
            localfiles::get_path_metadata,
        ])
        .run(tauri::generate_context!())
        .expect("❌error while running tauri application");
}



// #[tauri::command]
// // 查询当前路径下的云文档
// async fn check_cloud_paths(
//     // app_state: tauri::State<'_, AppState>,
//     user : User,
//     mongdb_url: String,
//     current_path: String,
// ) -> Result<Vec<String>, String> {
//     // let mut userdoc = from_appstate_get_userdoc(app_state).await?;
//     let mut user_doc = get_userdoc(user, mongdb_url).await?;
//     let mut paths = Vec::new();
//     while let Some(doc) = user_doc.next().await {
//         match doc {
//             Ok(document) => {
//                 let current_path_obj = Path::new(&current_path);
//                 let path = 
//                 document.get("path").and_then(|p| p.as_str()).ok_or("invalid path")?;
//                 if let Ok(rel_path) = Path::new(&path).strip_prefix(current_path_obj) {
//                     if rel_path.components().count() == 1 {
//                         paths.push(path.to_string());
//                     }
//                 }
//             }
//             Err(e) => return Err(format!("❌Failed to analyze: {}", e)),
//         }
//     };
//     Ok(paths)
//     // }
// }


